package org.ala.distributed_transaction_test.configuration;

import javax.sql.DataSource;

import org.ala.distributed_transaction_test.configuration.DBConfigure.DruidConfig;
import org.ala.distributed_transaction_test.configuration.DBConfigure.Item;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import com.alibaba.druid.pool.DruidDataSource;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;


/**
 * 数据库相关配置
 *
 * @author 骆毅(ala)
 * @date 2024年2月17日
 */
@Configuration
public class DBConfiguration {
	
	
	/**
	 * 公共配置项
	 */
	@Bean("databaseConfigure")
	@ConfigurationProperties(prefix="datasource")
	public DBConfigure dbConfigure() {
		DBConfigure c = new DBConfigure();
		return c;
	}

	
	/****************************************************************************************
	 * 
	 * test_db_1 库配置
	 * 
	 ****************************************************************************************/
	/**
	 * 数据源连接池
	 */
	@Bean("dataSourceTestDB1")
	public DataSource dataSourceTestDB1(
			@Qualifier("databaseConfigure") DBConfigure dbConfigure) {
		DruidDataSource ds = new DruidDataSource();
		Item item = dbConfigure.getItemHolder().get("test_db_1");
		DruidConfig cfg = item.getDruid();
		//	基础配置
		ds.setDriverClassName(item.getDriverClassName());
		ds.setUrl(item.getUrl());
		ds.setUsername(item.getUsername());
		ds.setPassword(item.getPassword());
		//	池子配置
		ds.setInitialSize(cfg.getInitialSize());
		ds.setMinIdle(cfg.getMinIdle());
		ds.setMaxActive(cfg.getMaxActive());
		ds.setMaxWait(cfg.getMaxWait());
		ds.setTimeBetweenEvictionRunsMillis(cfg.getTimeBetweenEevictionRunsMillis());
		ds.setMinEvictableIdleTimeMillis(cfg.getMinEvictableIdleTimeMillis());
		ds.setValidationQuery(cfg.getValidationQuery());
		ds.setTestWhileIdle(cfg.isTestWhileIdle());
		ds.setTestOnBorrow(cfg.isTestOnBorrow());
		ds.setTestOnReturn(cfg.isTestOnReturn());
		ds.setPoolPreparedStatements(cfg.isPoolPreparedStatements());
		ds.setMaxPoolPreparedStatementPerConnectionSize(cfg.getMaxPoolPreparedStatementPerConnectionSize());
		return ds;
	}
	/**
	 * 事务控制器
	 */
	@Bean("dataSourceTransactionManagerTestDB1")
	public DataSourceTransactionManager dataSourceTransactionManagerTestDB1(
			@Qualifier("dataSourceTestDB1") DataSource dataSource) {
		DataSourceTransactionManager txm = new DataSourceTransactionManager(dataSource);
		return txm;
	}
	/**
	 * SqlSessionFactory
	 * @throws Exception 
	 */
	@Bean("sqlSessionFactoryTestDB1")
	public SqlSessionFactory sqlSessionFactoryTestDB1(
			@Qualifier("dataSourceTestDB1") DataSource dataSource,
			@Qualifier("databaseConfigure") DBConfigure dbConfigure) throws Exception {
		SqlSessionFactoryBean fb = new SqlSessionFactoryBean();
		fb.setDataSource(dataSource);
		fb.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(dbConfigure.getItemHolder().get("test_db_1").getMapperLocations()));
		return fb.getObject();
	}
	/**
	 * sqlSessionTemplate
	 */
	@Bean("sqlSessionTemplateTestDB1")
	public SqlSessionTemplate sqlSessionTemplateTestDB1(
			@Qualifier("sqlSessionFactoryTestDB1") SqlSessionFactory sqlSessionFactory) {
		SqlSessionTemplate tpl = new SqlSessionTemplate(sqlSessionFactory);
		return tpl;
	}
	/**
	 * mapper接口扫描路径
	 */
	@Bean("mapperScannerConfigurerTestDB1")
    public MapperScannerConfigurer mapperScannerConfigurerTestDB1(
    		@Qualifier("sqlSessionFactoryTestDB1") SqlSessionFactory sqlSessionFactory){
        MapperScannerConfigurer msc = new MapperScannerConfigurer();
        msc.setBasePackage("org.ala.distributed_transaction_test.test_tx");
        msc.setSqlSessionFactoryBeanName("sqlSessionFactoryTestDB1");
        msc.setSqlSessionTemplateBeanName("sqlSessionTemplateTestDB1");
        msc.setNameGenerator(new BeanNameGenerator() {
			public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
				String[] beanClassNames = definition.getBeanClassName().split("\\.");
				String beanName = "testDB1" + beanClassNames[beanClassNames.length - 1];
				return beanName;
			}
		});
        return msc;
    }
	
	
	/****************************************************************************************
	 * 
	 * test_db_2 库配置
	 * 
	 ****************************************************************************************/
	/**
	 * 数据源连接池
	 */
	@Bean("dataSourceTestDB2")
	public DataSource dataSourceTestDB2(
			@Qualifier("databaseConfigure") DBConfigure dbConfigure) {
		DruidDataSource ds = new DruidDataSource();
		Item item = dbConfigure.getItemHolder().get("test_db_2");
		DruidConfig cfg = item.getDruid();
		//	基础配置
		ds.setDriverClassName(item.getDriverClassName());
		ds.setUrl(item.getUrl());
		ds.setUsername(item.getUsername());
		ds.setPassword(item.getPassword());
		//	池子配置
		ds.setInitialSize(cfg.getInitialSize());
		ds.setMinIdle(cfg.getMinIdle());
		ds.setMaxActive(cfg.getMaxActive());
		ds.setMaxWait(cfg.getMaxWait());
		ds.setTimeBetweenEvictionRunsMillis(cfg.getTimeBetweenEevictionRunsMillis());
		ds.setMinEvictableIdleTimeMillis(cfg.getMinEvictableIdleTimeMillis());
		ds.setValidationQuery(cfg.getValidationQuery());
		ds.setTestWhileIdle(cfg.isTestWhileIdle());
		ds.setTestOnBorrow(cfg.isTestOnBorrow());
		ds.setTestOnReturn(cfg.isTestOnReturn());
		ds.setPoolPreparedStatements(cfg.isPoolPreparedStatements());
		ds.setMaxPoolPreparedStatementPerConnectionSize(cfg.getMaxPoolPreparedStatementPerConnectionSize());
		return ds;
	}
	/**
	 * 事务控制器
	 */
	@Bean("dataSourceTransactionManagerTestDB2")
	public DataSourceTransactionManager dataSourceTransactionManagerTestDB2(
			@Qualifier("dataSourceTestDB2") DataSource dataSource) {
		DataSourceTransactionManager txm = new DataSourceTransactionManager(dataSource);
		return txm;
	}
	/**
	 * SqlSessionFactory
	 * @throws Exception 
	 */
	@Bean("sqlSessionFactoryTestDB2")
	public SqlSessionFactory sqlSessionFactoryTestDB2(
			@Qualifier("dataSourceTestDB2") DataSource dataSource,
			@Qualifier("databaseConfigure") DBConfigure dbConfigure) throws Exception {
		SqlSessionFactoryBean fb = new SqlSessionFactoryBean();
		fb.setDataSource(dataSource);
		fb.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(dbConfigure.getItemHolder().get("test_db_2").getMapperLocations()));
		fb.setPlugins(null);
		return fb.getObject();
	}
	/**
	 * sqlSessionTemplate
	 */
	@Bean("sqlSessionTemplateTestDB2")
	public SqlSessionTemplate sqlSessionTemplateTestDB2(
			@Qualifier("sqlSessionFactoryTestDB2") SqlSessionFactory sqlSessionFactory) {
		SqlSessionTemplate tpl = new SqlSessionTemplate(sqlSessionFactory);
		return tpl;
	}
	/**
	 * mapper接口扫描路径
	 */
	@Bean("mapperScannerConfigurerTestDB2")
    public MapperScannerConfigurer mapperScannerConfigurerTestDB2(
    		@Qualifier("sqlSessionFactoryTestDB2") SqlSessionFactory sqlSessionFactory){
        MapperScannerConfigurer msc = new MapperScannerConfigurer();
        msc.setBasePackage("org.ala.distributed_transaction_test.test_tx");
        msc.setSqlSessionFactoryBeanName("sqlSessionFactoryTestDB2");
        msc.setSqlSessionTemplateBeanName("sqlSessionTemplateTestDB2");
        msc.setNameGenerator(new BeanNameGenerator() {
			public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
				String[] beanClassNames = definition.getBeanClassName().split("\\.");
				String beanName = "testDB2" + beanClassNames[beanClassNames.length - 1];
				return beanName;
			}
		});
        return msc;
    }
	
	
	/**
	 * jedispool
	 */
	@Bean("testJedisPool")
	public JedisPool testJedisPool() {
		GenericObjectPoolConfig<Jedis> poolConfig = new GenericObjectPoolConfig<Jedis>();
		poolConfig.setMinIdle(5);
		poolConfig.setMaxTotal(100);
		JedisPool pool = new JedisPool(poolConfig, "localhost", 6379, 60000, "123456", 0);
		return pool;
	}
	
}
